﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.Net;
using System.IO;
using System.Security.Cryptography;

namespace WebCrawler
{
	public partial class frmMain : Form
	{
		private Crawler crawler = new Crawler("http://maximals.ru/");
		//private Crawler crawler = new Crawler("http://twitter.com/");
		//private Crawler crawler = new Crawler("http://yandex.ru/");
		//private Crawler crawler = new Crawler("http://google.ru/");
		//private Crawler crawler = new Crawler("http://interfax-russia.ru");
		//private Crawler crawler = new Crawler("https://www.google.com/accounts/ServiceLogin?service=reader&passive=1209600&continue=http://www.google.ru/reader/?hl%3Dru%26tab%3DTy&followup=http://www.google.ru/reader/?hl%3Dru%26tab%3DTy&hl=ru");

		private string directory = "favicons";

		private int iconsCount = 0;

		private const int BUFFER_SIZE = 8192;

		public frmMain()
		{
			InitializeComponent();

			if (!Directory.Exists(directory))
				Directory.CreateDirectory(directory);
		}

		private void btnStart_Click(object sender, EventArgs e)
		{
			crawler = new Crawler(cbxStart.Text);
			crawler.PageVisited += crawler_PageVisited;
			crawler.Run();
			btnStatus.Enabled = true;
		}

		private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
		{
			crawler.Stop();
		}


		void crawler_PageVisited(object sender, PageEventArgs e)
		{
			SetText(txtLog, e.WebResponse.ResponseUri.AbsoluteUri + Environment.NewLine);

			GetFavicons(e.WebResponse.ResponseUri, e.ResponseText);
		}

		protected void GetFavicons(Uri baseUri, string htmlPage)
		{
			Match m;
			/*if (baseUri.AbsoluteUri.Contains("loc/"))
				m = null;/**/

			string hrefPattern = "(<link\\s+rel\\s*=\\s*\"(shortcut )?icon\"\\s*href\\s*=\\s*(?:\"(?<href>[^\"]*)\"|(?<href>\\S+)))|(<link\\s+href\\s*=\\s*(?:\"(?<href>[^\"]*)\"|(?<href>\\S+))\\s*rel\\s*=\\s*\"(shortcut )?icon\")";

			m = Regex.Match(htmlPage, hrefPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
			List<string> hrefs = new List<string>();
			while (m.Success)
			{
				hrefs.Add(m.Groups["href"].ToString());
				m = m.NextMatch();
			}

			if (hrefs.Count < 1 && !hrefs.Contains("/favicon.ico"))
				hrefs.Add("/favicon.ico");

			foreach (string href in hrefs)
			{
				try
				{
					WebRequest req = WebRequest.Create(new Uri(baseUri, href));
					req.Timeout = 10000;
					WebResponse res = (WebResponse)(req.GetResponse());
					Stream st = res.GetResponseStream();
					BinaryReader binReader = new BinaryReader(st);
					BinaryWriter binWriter = new BinaryWriter(File.Open(directory + "/.favicon.temp", FileMode.Create));

					byte[] buffer = new byte[BUFFER_SIZE];
					int bytesRead = 0;
					int offset = 0;
					MD5 md5Hasher = MD5.Create();
					while ((bytesRead = binReader.Read(buffer, 0, BUFFER_SIZE)) > 0)
					{
						binWriter.Write(buffer, 0, bytesRead);
						offset += md5Hasher.TransformBlock(buffer, offset, bytesRead, buffer, offset);
					}
					binWriter.Close();
					md5Hasher.TransformFinalBlock(buffer, offset, 0);

					string filename = directory + "/" + GetMd5Hash(md5Hasher) + Path.GetExtension(href);
					binReader.Close();

					if (!File.Exists(filename))
					{
						File.Move(directory + "/.favicon.temp", filename);
						WriteRes(filename, baseUri.AbsoluteUri);
						iconsCount++;
						SetStatusText(lblIcons, "Иконок: " + iconsCount);

						if (iconsCount > 1000)
							crawler.Stop();
					}
					//else
						// Пока не удаляем
						//File.Delete("favicons/.favicon.temp");
				}
				catch (Exception ex)
				{
					Log.Write(ex);
				}
			}
		}



		string GetMd5Hash(MD5 md5Hasher)
		{
			byte[] data = md5Hasher.Hash;
			StringBuilder sBuilder = new StringBuilder();
			for (int i = 0; i < data.Length; i++)
			{
				sBuilder.Append(data[i].ToString("x2"));
			}
			return sBuilder.ToString();
		}


		public void WriteRes(string hash, string uri)
		{
			using (System.IO.StreamWriter log = System.IO.File.AppendText(directory + "/_results.log"))
			{
				log.WriteLine("{0}: {1}", hash, uri);
				log.Flush();
			}
		}


		delegate void SetTextCallback(TextBox textBox, string text);
		private void SetText(TextBox textBox, string text)
		{
			if (textBox.InvokeRequired)
			{
				SetTextCallback d = new SetTextCallback(SetText);
				if (this.InvokeRequired)
					this.Invoke(d, new object[] { textBox, text });
			}
			else
			{
				textBox.AppendText(text);
			}
		}

		delegate void SetStatusCallback(ToolStripStatusLabel label, string text);
		private void SetStatusText(ToolStripStatusLabel label, string text)
		{
			if (this.InvokeRequired)
			{
				SetStatusCallback d = new SetStatusCallback(SetStatusText);
				if (this.InvokeRequired)
					this.Invoke(d, new object[] { label, text });
			}
			else
			{
				label.Text = text;
			}
		}

		private void btnStatus_Click(object sender, EventArgs e)
		{
			MessageBox.Show(crawler.ThreadState.ToString());
		}
	}
}
